extends CharacterBody2D
enum State {
	IDLE,
	RUNNING,
	JUMP,
	FALL,
	LANDING,
}
var default_gravity:=ProjectSettings.get("physics/2d/default_gravity") as float
const RUN_SPEED :=160.0
const JUMP_VELOCITY :=-320.0
#是否是动画的第一帧
var is_first_tick :=false
#定义地面状态集合
const GROUND_STATES := [State.IDLE,State.RUNNING,State.LANDING]
const FLOOR_ACCELERATION := RUN_SPEED /0.2
const AIR_ACCELERATION := RUN_SPEED /0.02
@onready var sprite_2d = $Sprite2D
@onready var animation_player = $AnimationPlayer
#离开平台一小段时间仍然能起跳
@onready var coyote_timer: Timer = $CoyoteTimer
#大小跳 如果没有剩余时间了则不允许起跳
@onready var jump_request_timer: Timer = $JumpRequestTimer

#使用事件回调函数
func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("jump"):
		jump_request_timer.start()
	#短按轻跳，长按大跳
	if event.is_action_released("jump"):
		jump_request_timer.stop()
		if velocity.y < JUMP_VELOCITY /2:
			velocity.y = JUMP_VELOCITY /2


#每个物理帧调用一次
func tick_physics(state:State,delta: float) ->void:
	match state:
		State.IDLE:
			move(default_gravity,delta)
		State.RUNNING:
			move(default_gravity,delta)
		State.JUMP:
			move(0.0 if is_first_tick else default_gravity, delta)
		State.FALL:
			move(default_gravity,delta)
		State.LANDING:
			stand(delta)
	is_first_tick = false

func move(gravity:float,delta:float) -> void:
	var direction := Input.get_axis("move_left","move_right")
	var acceleration :=FLOOR_ACCELERATION if is_on_floor() else AIR_ACCELERATION
	velocity.x = move_toward(velocity.x,direction * RUN_SPEED,acceleration*delta)
	velocity.y += gravity * delta
	
	if not is_zero_approx(direction):
		sprite_2d.flip_h = direction < 0
	
	move_and_slide()

func stand(delta:float) ->void:
	var acceleration :=FLOOR_ACCELERATION if is_on_floor() else AIR_ACCELERATION
	velocity.x = move_toward(velocity.x,0.0,acceleration*delta)
	velocity.y += default_gravity * delta
	move_and_slide()

func get_next_state(state:State) ->State:
	#获取输入事件
	var direction :=Input.get_axis("move_left","move_right")
	#通过判断是否停止输入左或者右以及x轴的方向为0的情况下，判断是站立状态
	var is_still_standing := is_zero_approx(direction) and is_zero_approx(velocity.x)
	#在地板上或在郊狼时间内，表示能起跳
	var can_jump := is_on_floor() or coyote_timer.time_left >0
	#应该起跳的状态
	var should_jump := can_jump and jump_request_timer.time_left >0
	#直接返回起跳状态
	if should_jump:
		return State.JUMP
	match state:
		State.IDLE:
			if not is_on_floor():
				return State.FALL
			if not is_still_standing:
				return State.RUNNING
		State.RUNNING:
			if not is_on_floor():
				return State.FALL
			if is_still_standing:
				return State.IDLE
		State.JUMP:
			if velocity.y >=0:
				return State.FALL
			pass
		State.FALL:
			if is_on_floor():
				return State.LANDING if is_still_standing else State.RUNNING
		State.LANDING:
			if not animation_player.is_playing():
				return State.IDLE
	return state

func transition_state(from:State,to:State)->void:
	if from not in GROUND_STATES and to in GROUND_STATES:
		coyote_timer.stop()
	match to:
		State.IDLE:
			animation_player.play("idle")
		State.RUNNING:
			animation_player.play("running")
		State.JUMP:
			animation_player.play("jump")
			#到达最大速度时停止计时器
			velocity.y = JUMP_VELOCITY
			coyote_timer.stop()
			jump_request_timer.stop()
		State.FALL:
			animation_player.play("fall")
			if from in GROUND_STATES:
				coyote_timer.start()
		State.LANDING:
			animation_player.play("landing")
	is_first_tick = true
